package com.sh.data.engine.domain.base.service.impl;

import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.domain.base.model.ChunkFileUploadDomain;
import com.sh.data.engine.domain.base.model.FileUploadResultDomain;
import com.sh.data.engine.domain.base.model.FileUrlDomain;
import com.sh.data.engine.domain.base.model.param.ChunkFileUploadParam;
import com.sh.data.engine.domain.base.service.FileService;
import com.sh.data.engine.infrastructure.config.FileStorageConfiguration;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

/**
 * @author: mengzheng.mhc
 * @date: 2024/6/11 9:41
 */
@Slf4j
@Service
@ConditionalOnProperty(value = "data.engine.file-storage.type", havingValue = "nfs", matchIfMissing = true)
public class NFSFileServiceImpl implements FileService {

    @Autowired
    private FileStorageConfiguration fileStorageConfiguration;

    @Autowired
    private Environment environment;

    private File dirFile;

    @PostConstruct
    public void init() {
        final String dir = fileStorageConfiguration.getDir();

        if (StringUtils.isBlank(dir)) {
            throw new RuntimeException("must config the property : data.engine.file-storage.dir");
        }

        dirFile = new File(dir);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }
    }

    @Override
    public FileUploadResultDomain upload(MultipartFile multipartFile) throws Exception {
        return upload(multipartFile, null, false);
    }

    @Override
    public FileUploadResultDomain upload(MultipartFile multipartFile, boolean uuidFileName)
        throws Exception {
        return upload(multipartFile, null, uuidFileName);
    }

    @Override
    public FileUploadResultDomain upload(MultipartFile multipartFile, String fileRelativeDirPath)
        throws Exception {
        return upload(multipartFile, fileRelativeDirPath, false);
    }

    @Override
    public FileUploadResultDomain upload(
        MultipartFile multipartFile, String fileRelativeDirPath, boolean uuidFileName)
        throws Exception {
        final String originalFilename = multipartFile.getOriginalFilename();
        final InputStream inputStream = multipartFile.getInputStream();

        String fileName = originalFilename;

        if (uuidFileName) {
            String suffix =
                originalFilename.contains(".")
                    ? originalFilename.substring(originalFilename.lastIndexOf("."))
                    : "";
            fileName = UUID.randomUUID() + suffix;
        }

        String filePath;
        if (StringUtils.isBlank(fileRelativeDirPath)) {
            filePath = dirFile.getAbsolutePath() + File.separator + fileName;
        } else {
            filePath = dirFile.getAbsolutePath() + fileRelativeDirPath + File.separator + fileName;
        }

        File file = new File(filePath);
        FileUtils.copyInputStreamToFile(inputStream, file);

        FileUploadResultDomain domain = new FileUploadResultDomain();
        domain.setFileName(fileName);
        domain.setOriginalFilename(originalFilename);
        domain.setFilePath(filePath);

        final String contextPath = environment.getProperty("server.servlet.context-path", "");

        final HttpServletRequest request = ServletUtils.getRequest();
        String uriPrefix =
            request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();

        final String decode = URLDecoder.decode(filePath, StandardCharsets.UTF_8);

        String filePreviewUrl = uriPrefix + contextPath + "/api/v1/file/getFileForPreview?filePath=" + decode;
        String fileDownloadUrl =
            uriPrefix + contextPath + "/file/getFileForDownload?filePath=" + decode;

        domain.setFileDownloadUrl(fileDownloadUrl);
        domain.setFilePreviewUrl(filePreviewUrl);

        return domain;
    }

    @Override
    public FileUploadResultDomain uploadHiveSite(
        MultipartFile multipartFile, String fileRelativeDirPath, boolean uuidFileName)
        throws Exception {
        final String originalFilename = multipartFile.getOriginalFilename();
        final InputStream inputStream = multipartFile.getInputStream();

        String fileName = "hive-site.xml";

        if (uuidFileName) {
            String suffix =
                originalFilename.contains(".")
                    ? originalFilename.substring(originalFilename.lastIndexOf("."))
                    : "";
            fileName = UUID.randomUUID() + suffix;
        }

        String filePath;
        if (StringUtils.isBlank(fileRelativeDirPath)) {
            filePath = dirFile.getAbsolutePath() + File.separator + fileName;
        } else {
            filePath =
                dirFile.getAbsolutePath()
                    + File.separator
                    + fileRelativeDirPath
                    + File.separator
                    + fileName;
        }

        File file = new File(filePath);
        FileUtils.copyInputStreamToFile(inputStream, file);

        FileUploadResultDomain domain = new FileUploadResultDomain();
        domain.setFileName(fileName);
        domain.setOriginalFilename(originalFilename);
        domain.setFilePath(filePath);

        final String contextPath = environment.getProperty("server.servlet.context-path", "");

        final HttpServletRequest request = ServletUtils.getRequest();
        String uriPrefix =
            request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();

        final String decode = URLDecoder.decode(filePath, StandardCharsets.UTF_8);

        String filePreviewUrl = uriPrefix + contextPath + "/api/v1/file/getFileForPreview?filePath=" + decode;
        String fileDownloadUrl =
            uriPrefix + contextPath + "/api/v1/file/getFileForDownload?filePath=" + decode;

        domain.setFileDownloadUrl(fileDownloadUrl);
        domain.setFilePreviewUrl(filePreviewUrl);

        return domain;
    }

    @Override
    public ChunkFileUploadDomain uploadByChunk(
        javax.servlet.http.HttpServletRequest request, ChunkFileUploadParam param) {
        return null;
    }

    @Override
    public File getFileByPath(String filePath) {
        File file = new File(filePath);
        return file;
    }

    @Override
    public FileUrlDomain getFileUrlByPath(String filePath, javax.servlet.http.HttpServletRequest request) {
        if (null == filePath) {
            return null;
        }
        FileUrlDomain domain = new FileUrlDomain();

        final String contextPath = environment.getProperty("server.servlet.context-path", "");

        String uriPrefix =
            request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();

        String decode = "";
        decode = URLDecoder.decode(filePath, StandardCharsets.UTF_8);

        String filePreviewUrl = uriPrefix + contextPath + "/api/v1/file/getFileForPreview?filePath=" + decode;
        String fileDownloadUrl =
            uriPrefix + contextPath + "/api/v1/file/getFileForDownload?filePath=" + decode;

        domain.setFileDownloadUrl(fileDownloadUrl);
        domain.setFilePreviewUrl(filePreviewUrl);

        return domain;
    }
}
